
#ifndef H_X_LOGGER_H_
#define H_X_LOGGER_H_

#include "x_logstream.h"
#include <cstdio>
#include <mutex>
#include <memory>
#include "x_logfile.h"

namespace x_log
{
//输出到终端
void standOutput(const char* msg, int len);
void standFlush();
//输出到文件
void defaultOutPut(const char* msg, int len);
void defaultFlush();

//针对线程ID的获取进行封装
namespace curentThread
{
    //线程局部存储
    extern __thread int  t_cachedTid;
    extern __thread char t_tidString[32]; //字符串格式的线程ID
    extern __thread int  t_tidStrLen; //字符串化的线程的ID长度
    void cacheTid();
    inline int getThreadID()
    {
        if (__builtin_expect(t_cachedTid == 0, 0))
        {
            cacheTid();
        }
        return t_cachedTid;
    }

    inline const char* tidtoString()
    {
        return t_tidString;
    }

    inline int tidStrLength()
    {
        return t_tidStrLen;
    }
} //namespace curentThread


//封装简单的时间戳类,时间精确到微妙
class Timestamp
{
public:
    Timestamp()= default;
    explicit Timestamp(int64_t microSeconds) : m_iMicroSeconds(microSeconds)
    {
    }
    ~Timestamp()= default;
    static Timestamp now();
    // 外部使用
    int64_t getMicroSecondsSinceEpoch() const { return m_iMicroSeconds; }
    time_t getSecondsSinceEpoch() const
    { return static_cast<time_t>(m_iMicroSeconds / kMicroSecondsPerSecond); }
    static const int kMicroSecondsPerSecond = 1000 * 1000;
private:
    int64_t m_iMicroSeconds{};
}; //class CTimestamp


//2022/02/22:用于获取源文件名称(不含绝对路径)
class BaseFile
{
public:
    template<int N>
    BaseFile(const char (&array)[N]) : data_(array), size_(N - 1)
    {
        //查找最后一个'/'
        const char* ptr = strrchr(data_, '/');
        if (nullptr != ptr)
        {
            data_ = ptr + 1;
            size_ -= static_cast<int>(data_ - array);
        }
    }
    BaseFile(const char* filename) : data_(filename)
    {
        const char* ptr = strrchr(filename, '/');
        if (nullptr != ptr)
        {
            data_ = ptr + 1;
        }
        size_ = static_cast<int>(strlen(data_));
    }
public:
    const char* data_;
    int size_;
}; //class BaseFile

extern std::mutex LogFileLocker;
extern std::unique_ptr<CLogFile> g_file_out;

class CLogger
{
public:
    enum LogLevel
    {
      X_TRACE,
      X_DEBUG,
      X_INFO,
      X_WARN,
      X_ERROR,
      X_FATAL,
      NUM_LOG_LEVELS,
    };
    CLogger(BaseFile filename, int line);
    CLogger(BaseFile filename, int line, int syserrno);
    CLogger(BaseFile filename, int line, LogLevel level);
    CLogger(BaseFile filename, int line, LogLevel level, const char* funcname);
    ~CLogger();

    CLogStream & stream() { return m_impl.m_stream; }
    static LogLevel logLevel();
    static void setLogLevel(LogLevel level);

    //定义日志内容的输出接口
    typedef void (*LogOutPutFunc)(const char* msg, int len);
    typedef void (*LogFlushFunc)();
    static void setLogOutPut(LogOutPutFunc out);
    static void setFlush(LogFlushFunc flush);
    static void setLogFileName(std::string file_name);
    static std::mutex OutMutex_;
    static LogOutPutFunc LogOut;
    static std::mutex FlushMutex_;
    static LogFlushFunc LogFlush;
    static std::string LogFileName;
private:
    class Impl
    {
    public:
        typedef CLogger::LogLevel LogLevel;
        Impl(LogLevel level, const BaseFile& filename, int line);
        void formatTime();
        void ends();
        Timestamp m_time;
        CLogStream m_stream;
        LogLevel m_level;
        std::string m_filename;
        int m_line;
    }; //class Impl
    Impl m_impl;
}; //class CLogger

extern CLogger::LogLevel g_logLevel;
extern const char* LogLevelName[CLogger::NUM_LOG_LEVELS];
inline CLogger::LogLevel CLogger::logLevel()
{
    return g_logLevel;
}

} //namespace x_log


#endif

